package com.hdax.dm.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdax.dm.dtos.item.AreaDto;
import com.hdax.dm.dtos.item.ItemRowsDto;
import com.hdax.dm.dtos.item.ItemSearchResultDto;
import com.hdax.dm.entity.base.Area;
import com.hdax.dm.entity.item.DmItemType;
import com.hdax.dm.feign.item.BaseFeign;
import com.hdax.dm.mappers.DmItemTypeMapper;
import com.hdax.dm.service.ItemSearchService;
import com.hdax.dm.vo.ItemSearchVo;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Service
public class ItemSearchServiceImpl extends ServiceImpl<DmItemTypeMapper, DmItemType> implements ItemSearchService {

    @Autowired
    private BaseFeign baseFeign;
    @Autowired
    private RestHighLevelClient client;

    @Override
    public List<DmItemType> itemTypes(Long parent) {
        QueryWrapper<DmItemType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent",parent);
        return list(queryWrapper);
    }

    @Override
    public List<AreaDto> queryCities() {
        List<Area> areas = baseFeign.areas();
        List<AreaDto> areaDtos = new ArrayList<>();
        areas.forEach(a->{
            AreaDto dto = AreaDto.builder()
                    .id(a.getId())
                    .name(a.getName())
                    .build();
            areaDtos.add(dto);
        });
        return areaDtos;
    }

    /**
     * 通过调用ElasticSearch快速检索数据
     * @param vo
     * @return
     */
    @Override
    public ItemSearchResultDto querygoodsinfos(ItemSearchVo vo) throws Exception{
        SearchRequest request = new SearchRequest("items");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //Elasticsearch多条件搜索
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //由于页面的条件是不确定个数的，所以通过判断
        if(vo.getKeyword()!=null && !vo.getKeyword().trim().equals("")){
            //语法高亮
            HighlightBuilder.Field highlightFiled =
                    new HighlightBuilder.Field("itemname");
            highlightFiled.highlighterType("unified");
            highlightBuilder.field(highlightFiled);
            //拼接itemname的匹配度查询
            boolQueryBuilder.must(QueryBuilders.matchQuery("itemname",vo.getKeyword()));
            //should:不影响查询结果条数，但是影响排名评分
            boolQueryBuilder.should(QueryBuilders.matchQuery("abstractmessage",vo.getKeyword()));
        }
        //所在地区查询
        if(vo.getAreaId()!=0){
            boolQueryBuilder.must(QueryBuilders.termQuery("areaid",vo.getAreaId()));
        }
        //and
        //一二级分类
        if(vo.getItemTypeId1()!=0){
            boolQueryBuilder.must(QueryBuilders.termQuery("itemtype1id",vo.getItemTypeId1()));
        }
        if(vo.getItemTypeId2()!=0){
            boolQueryBuilder.must(QueryBuilders.termQuery("itemtype2id",vo.getItemTypeId2()));
        }

        //时间范围查询
        if(vo.getStartTime()!="" && vo.getEndTime()!=""){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("starttime");
            rangeQueryBuilder.gte(vo.getStartTime()+"T00:00:00");
            rangeQueryBuilder.lte(vo.getEndTime()+"T23:59:59");
            boolQueryBuilder.must(rangeQueryBuilder);
        }
        //排序
        if(vo.getSort().equals("recommend"))
            builder.sort("isrecommend", SortOrder.DESC);
        if(vo.getSort().equals("recentShow"))
            builder.sort("starttime", SortOrder.DESC);
        if(vo.getSort().equals("reccentSell"))
            builder.sort("createtime",SortOrder.DESC);

        //执行查询封装
        builder.query(boolQueryBuilder);

        //设置高亮的样式
        highlightBuilder.requireFieldMatch(true);
        highlightBuilder.preTags("<span style='color:red;background-color:orange'>");
        highlightBuilder.postTags("</span>");
        builder.highlighter(highlightBuilder);

        //分页查询
        //from 默认0  currentPage-1) * pageSize
        builder.from((vo.getCurrentPage()-1)*vo.getPageSize());
        builder.size(vo.getPageSize());
        request.source(builder);

        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        ItemSearchResultDto resultDto = new ItemSearchResultDto();
        SearchHit[] searchHits = response.getHits().getHits();

        resultDto.setCurrentPage(vo.getCurrentPage());
        resultDto.setPageSize(vo.getPageSize());
        resultDto.setRows(new ArrayList<ItemRowsDto>());
        resultDto.setPageCount(response.getHits().getTotalHits().value % vo.getPageSize() == 0?
                response.getHits().getTotalHits().value / vo.getPageSize():
                response.getHits().getTotalHits().value / vo.getPageSize()+1);

        for (int i = 0; i < searchHits.length; i++) {
            //每一行搜索到的商品数据
            ItemRowsDto rowsDto = JSON.parseObject(searchHits[i].getSourceAsString(), ItemRowsDto.class);
            //远程调用
            rowsDto.setImgUrl(baseFeign.image(rowsDto.getId())==null?"":baseFeign.image(rowsDto.getId()).getImgUrl());
            if(vo.getKeyword()!=null && !vo.getKeyword().trim().equals(""))
                rowsDto.setItemName(StringUtils.arrayToDelimitedString(searchHits[i].getHighlightFields().get("itemname").getFragments(), ""));
            resultDto.getRows().add(rowsDto);
        }

        resultDto.setTotal(response.getHits().getTotalHits().value);
        return resultDto;
    }
}
